var _ctCsvMdLast = { rows: [], aligns: [], header: true };
function _ctParseDelimited(text, delim) {
var rows = [];
var row = [];
var field = '';
var inQuotes = false;
var s = text;
var i = 0;
while (i < s.length) {
var c = s.charAt(i);
if (inQuotes) {
if (c === '\"' && s.charAt(i+1) === '\"') { field += '\"'; i += 2; continue; }
if (c === '\"') { inQuotes = false; i++; continue; }
field += c; i++; continue;
}
if (c === '\"' && field.trim() === '') { field = ''; inQuotes = true; i++; continue; }
if (c === delim) { row.push(field); field = ''; i++; continue; }
if (c === '\n') { row.push(field); rows.push(row); row = []; field = ''; i++; continue; }
field += c; i++;
}
if (field !== '' || row.length) { row.push(field); rows.push(row); }
return rows;
}
// Pick the delimiter that splits the first few lines into the most consistent number of columns.
function _ctDetectDelimiter(text) {
var lines = text.split('\n').filter(function(l){ return l.trim() !== ''; }).slice(0, 20);
var candidates = ['\t', ',', ';', '|'];
var best = ',', bestScore = 0;
candidates.forEach(function(d){
var counts = lines.map(function(l){
var n = 0, q = false;
for (var i = 0; i < l.length; i++) {
var c = l.charAt(i);
if (c === '\"') q = !q;
else if (c === d && !q) n++;
}
return n;
});
if (!counts.length || counts[0] === 0) return;
var same = counts.filter(function(n){ return n === counts[0]; }).length;
var score = (same / counts.length) * 100 + counts[0];
if (score > bestScore) { bestScore = score; best = d; }
});
return best;
}
function _ctCellWidth(s) {
var w = 0;
for (var ch of s) {
var cp = ch.codePointAt(0);
if (cp >= 0x300 && cp <= 0x36f) continue;
if (cp === 0x200d || (cp >= 0xfe00 && cp <= 0xfe0f)) continue;
w += ((cp >= 0x1100 && cp <= 0x115f) || (cp >= 0x2e80 && cp <= 0xa4cf) || (cp >= 0xac00 && cp <= 0xd7a3)
|| (cp >= 0xf900 && cp <= 0xfaff) || (cp >= 0xfe30 && cp <= 0xfe4f) || (cp >= 0xff00 && cp <= 0xff60)
|| (cp >= 0xffe0 && cp <= 0xffe6) || (cp >= 0x1f300 && cp <= 0x1faff) || (cp >= 0x20000 && cp <= 0x3fffd)) ? 2 : 1;
}
return w;
}
function _ctMdEscape(cell) {
return String(cell == null ? '' : cell)
.replace(/\|/g, '\\|')
.replace(/\n/g, '
');
}
function _ctIsNumber(s) {
return /^[-+(]?[$€£¥]?\s?\d[\d,\s]*(\.\d+)?\)?\s?%?$/.test(s) || /^[-+]?\.\d+%?$/.test(s);
}
function _ctOpt(id, fallback) {
var el = document.getElementById(id);
if (!el) return fallback;
return el.type === 'checkbox' ? el.checked : el.value;
}
function convert(input) {
var text = (input || '').replace(/^/, '').replace(/\r\n/g, '\n').replace(/\r/g, '\n');
var status = document.getElementById('csvmd-status');
var delimChoice = _ctOpt('csvmd-delim', 'auto');
var delim = delimChoice === 'auto' ? _ctDetectDelimiter(text) : (delimChoice === 'tab' ? '\t' : delimChoice);
var header = _ctOpt('csvmd-header', true);
var align = _ctOpt('csvmd-align', 'auto');
var pad = _ctOpt('csvmd-pad', true);
var trim = _ctOpt('csvmd-trim', true);
var rows = _ctParseDelimited(text, delim).filter(function(r){
return r.some(function(c){ return c.trim() !== ''; });
});
// A pasted Markdown-style table has leading and trailing pipes; drop the empty edge columns.
if (delim === '|' && rows.length && rows.every(function(r){ return r.length > 1 && r[0].trim() === '' && r[r.length-1].trim() === ''; })) {
rows = rows.map(function(r){ return r.slice(1, -1); });
rows = rows.filter(function(r){ return !r.every(function(c){ return /^\s*:?-+:?\s*$/.test(c); }); });
}
if (trim) rows = rows.map(function(r){ return r.map(function(c){ return c.trim(); }); });
if (!rows.length) {
_ctCsvMdLast = { rows: [], aligns: [], header: header };
_ctCsvMdRenderPreview();
if (status) status.textContent = '';
return '';
}
var width = 0;
rows.forEach(function(r){ if (r.length > width) width = r.length; });
rows = rows.map(function(r){ r = r.slice(); while (r.length < width) r.push(''); return r; });
var head = header ? rows[0] : rows[0].map(function(){ return ''; });
var body = header ? rows.slice(1) : rows;
var aligns = [];
for (var c = 0; c < width; c++) {
if (align === 'auto') {
var vals = body.map(function(r){ return r[c].trim(); }).filter(function(v){ return v !== ''; });
aligns.push(vals.length && vals.every(_ctIsNumber) ? 'right' : '');
} else {
aligns.push(align === 'none' ? '' : align);
}
}
var cells = [head].concat(body).map(function(r){ return r.map(_ctMdEscape); });
var widths = [];
for (var c = 0; c < width; c++) {
var w = 3;
if (pad) cells.forEach(function(r){ var cw = _ctCellWidth(r[c]); if (cw > w) w = cw; });
widths.push(w);
}
function padCell(s, c) {
if (!pad) return s;
var gap = widths[c] - _ctCellWidth(s);
if (gap <= 0) return s;
if (aligns[c] === 'right') return ' '.repeat(gap) + s;
if (aligns[c] === 'center') { var l = Math.floor(gap / 2); return ' '.repeat(l) + s + ' '.repeat(gap - l); }
return s + ' '.repeat(gap);
}
function line(r) {
return '| ' + r.map(padCell).join(' | ') + ' |';
}
var sep = '| ' + widths.map(function(w, c){
var a = aligns[c];
var n = pad ? w : 3;
if (a === 'left') return ':' + '-'.repeat(n - 1);
if (a === 'right') return '-'.repeat(n - 1) + ':';
if (a === 'center') return ':' + '-'.repeat(Math.max(1, n - 2)) + ':';
return '-'.repeat(n);
}).join(' | ') + ' |';
var out = [line(cells[0]), sep].concat(cells.slice(1).map(line)).join('\n');
_ctCsvMdLast = { rows: [head].concat(body), aligns: aligns, header: header };
_ctCsvMdRenderPreview();
if (status) {
var names = { '\t': 'tab', ',': 'comma', ';': 'semicolon', '|': 'pipe' };
status.textContent = (delimChoice === 'auto' ? 'Detected ' + names[delim] + ' separated. ' : '')
+ width + ' column' + (width === 1 ? '' : 's') + ', ' + body.length + ' row' + (body.length === 1 ? '' : 's');
}
return out;
}
function _ctCsvMdRenderPreview() {
var wrap = document.getElementById('csvmd-preview');
if (!wrap) return;
var d = _ctCsvMdLast;
if (!d.rows.length) { wrap.style.display = 'none'; wrap.innerHTML = ''; return; }
function esc(s) { return String(s).replace(/[&<>]/g, function(ch){ return ({'&':'&','<':'<','>':'>'})[ch]; }).replace(/\n/g, '
'); }
function cell(tag, s, c) {
var a = d.aligns[c] ? ' style=\"text-align:' + d.aligns[c] + '\"' : '';
return '<' + tag + a + '>' + esc(s) + '' + tag + '>';
}
var html = '